import { isNaNOrNull } from './number-util'

export enum SpeedType {
  CAS = 'CAS',
  TAS = 'TAS',
  Mach = 'Mach'
}

export enum SpeedUnit {
  MPS = 'MPS',
  KMPH = 'KMPH',
  KT = 'KT',
  FTPM = 'FTPM' // ft/min
}

export const SpeedUnitName: Record<SpeedUnit, string> = {
  MPS: 'm/s',
  KMPH: 'km/h',
  KT: 'kt',
  FTPM: 'ft/min'
}

export function speedUnitName(u: SpeedUnit): string {
  return SpeedUnitName[u]
}

export const SpeedConst = {
  KT2MPS: 1852 / 3600,
  KMPH2MPS: 1 / 3.6
}

export function mps2Kt(v: number): number {
  return v / 0.514444
}

export function mps2Kmph(v: number): number {
  return v * 3.6
}

export function mps2ftpm(v: number): number {
  return v * 196.8504
}
export function kt2Mps(v: number): number {
  return v * 0.514444
}

export function kmph2Mps(v: number): number {
  return v / 3.6
}

export function ftpm2Mps(v: number): number {
  return v / 196.8504
}
export function fromMpsConvert(unit: SpeedUnit): (mps: number) => number {
  if (unit === SpeedUnit.FTPM) {
    return mps2ftpm
  }
  if (unit === SpeedUnit.KMPH) {
    return mps2Kmph
  }
  if (unit === SpeedUnit.KT) {
    return mps2Kt
  }
  return (e) => e
}

export function fromMps(mps: number, unit: SpeedUnit): number {
  return fromMpsConvert(unit)(mps)
}

export function toMpsConvert(unit: SpeedUnit): (v: number) => number {
  if (unit === SpeedUnit.FTPM) {
    return ftpm2Mps
  }
  if (unit === SpeedUnit.KMPH) {
    return kmph2Mps
  }
  if (unit === SpeedUnit.KT) {
    return kt2Mps
  }
  return (e) => e
}

export function toMps(v: number, unit: SpeedUnit): number {
  return toMpsConvert(unit)(v)
}

export class SpeedModel {
  readonly NONE: number
  constructor(invalid: number) {
    this.NONE = invalid
  }

  public invalid(n: number): boolean {
    return isNaN(n) || n <= -this.NONE || n >= this.NONE
  }
  public valid(n: number): boolean {
    return !this.invalid(n)
  }

  public toMps(v: number, u: SpeedUnit): number {
    if (this.invalid(v)) {
      return this.NONE
    }
    return toMps(v, u)
  }

  public fromMps(v: number, u: SpeedUnit): number {
    if (this.invalid(v)) {
      return this.NONE
    }
    return fromMps(v, u)
  }

  public str2mps(s: string | undefined, u: SpeedUnit): number {
    if (!s) {
      return this.NONE
    }
    s = s.trim()
    if (s === '') {
      return this.NONE
    }
    const i = parseFloat(s)
    if (isNaN(i)) {
      return this.NONE
    }
    return toMps(i, u)
  }

  public mps2str(mps: number, u: SpeedUnit, fixed: number = 3): string {
    if (isNaNOrNull(mps)) {
      return ''
    }
    if (this.invalid(mps)) {
      return ''
    }
    return fromMps(mps, u).toFixed(fixed)
  }

  public mps2strWithUnit(mps: number, u: SpeedUnit, fixed: number = 3): string {
    if (isNaNOrNull(mps)) {
      return ''
    }
    if (this.invalid(mps)) {
      return ''
    }
    return fromMps(mps, u).toFixed(fixed) + SpeedUnitName[u]
  }
}

const SPEED_NONE = 999.0
export const SPEED = new SpeedModel(SPEED_NONE)
